﻿# coding: utf-8

import os
import wx
import wx.lib.agw.floatspin as FS

import TerrainHeightBrush

BRUSH_SIZE = 64

class wxPanelTerrainHeight(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        
        # Create brush image list
        self._ilBrush = wx.ImageList(BRUSH_SIZE, BRUSH_SIZE)

        # Layout
        sizerBrushList = self.__CreateUIBrushList()
        sizerBrushParam = self.__CreateUIBrushParam()
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(sizerBrushList, 1, wx.ALL|wx.EXPAND, border = 10)
        sizer.Add(sizerBrushParam, 0, wx.ALL|wx.EXPAND, border = 10)
        self.SetSizer(sizer)
        
        # Bind brush list event.
        self.Bind(wx.EVT_CONTEXT_MENU, self.__OnContextMenu)
        self._idMenuAddBrush = wx.NewId()
        self._idMenuRemoveBrush = wx.NewId()
        self.Bind(wx.EVT_MENU, self.__OnMenuAddBrush, id = self._idMenuAddBrush)
        self.Bind(wx.EVT_MENU, self.__OnMenuRemoveBrush, id = self._idMenuRemoveBrush)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__OnBrushSelected, self._listBrush)
        
        # Bind brush parameter event.
        self._fsBrushSize.Bind(FS.EVT_FLOATSPIN, self.__OnFloatSpinBrushSize)
        self._fsBrushPowerFactor.Bind(FS.EVT_FLOATSPIN, self.__OnFloatSpinBrushPowerFactor)
        self._fsBrushPowerOffset.Bind(FS.EVT_FLOATSPIN, self.__OnFloatSpinBrushPowerOffset)
        self._ckUpDown.Bind(wx.EVT_CHECKBOX, self.__OnCheckBoxUpDown)
        
    def LoadHeightBrush(self):
        for path in GLOBAL_SETTING._terrainHeightBrushList:
            if not TERRAIN_EDITOR.AddTerrainHeightBrush(path):
                continue
                
            fullPath = GLOBAL_SETTING._workDir + path
            bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
            if bmp:
                self.__AddBrush(bmp, path)
        
    def __OnFloatSpinBrushSize(self, e):
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        size = self._fsBrushSize.GetValue()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentHeightBrushHandle()
        if brushCoreHandle:
            TerrainHeightBrush.SetSize(brushCoreHandle, size)
        
    def __OnFloatSpinBrushPowerFactor(self, e):
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        powerFactor = self._fsBrushPowerFactor.GetValue()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentHeightBrushHandle()
        if brushCoreHandle:
            TerrainHeightBrush.SetPowerFactor(brushCoreHandle, powerFactor)        
            
    def __OnFloatSpinBrushPowerOffset(self, e):
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        powerOffset = self._fsBrushPowerOffset.GetValue()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentHeightBrushHandle()
        if brushCoreHandle:
            TerrainHeightBrush.SetPowerOffset(brushCoreHandle, powerOffset)
            
    def __OnCheckBoxUpDown(self, e):
        if not TERRAIN_EDITOR.IsEditing():
            return
            
        checked = e.IsChecked()
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentHeightBrushHandle()
        if brushCoreHandle:
            TerrainHeightBrush.SetPaintUp(brushCoreHandle, checked)

    def __CreateUIBrushList(self):
        """ Create brush list """
        
        self._listBrush = wx.ListCtrl(self, wx.NewId(), style = wx.LC_ICON|wx.LC_SINGLE_SEL|wx.LC_AUTOARRANGE)
        self._listBrush.SetImageList(self._ilBrush, wx.IMAGE_LIST_NORMAL)        
        sizer = wx.StaticBoxSizer(wx.StaticBox(self, -1, TD.TERRAIN_HEIGHT_BRUSH_LIST), wx.VERTICAL)        
        sizer.Add(self._listBrush, 1, wx.ALL|wx.EXPAND, border = 5)
        return sizer
        
    def __CreateUIBrushParam(self):
        """ Create brush parameter UI """
        
        # Height brush size
        staticBrushSize = wx.StaticText(self, -1, TD.TERRAIN_HEIGHT_BRUSH_SIZE)
        self._fsBrushSize = FS.FloatSpin(self, -1, min_val = 10.0, max_val = 1200.0, increment = 10.0, agwStyle = FS.FS_RIGHT)
        self._fsBrushSize.SetDigits(2)
        self._fsBrushSize.SetFormat('%f')
        sizerBrushSize = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushSize.Add(staticBrushSize, 0, wx.CENTER, border = 5)
        sizerBrushSize.Add(self._fsBrushSize, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        # Height power factor.
        staticBrushPowerFactor = wx.StaticText(self, -1, TD.TERRAIN_HEIGHT_BRUSH_POWER_FACTOR)
        self._fsBrushPowerFactor = FS.FloatSpin(self, -1, min_val = 0, max_val = 10.0, increment = 0.1, agwStyle = FS.FS_RIGHT)
        self._fsBrushPowerFactor.SetDigits(2)
        self._fsBrushPowerFactor.SetFormat('%f')
        sizerBrushPowerFactor = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushPowerFactor.Add(staticBrushPowerFactor, 0, wx.CENTER, border = 5)
        sizerBrushPowerFactor.Add(self._fsBrushPowerFactor, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        # Height power offset.
        staticBrushPowerOffset = wx.StaticText(self, -1, TD.TERRAIN_HEIGHT_BRUSH_POWER_OFFSET)
        self._fsBrushPowerOffset = FS.FloatSpin(self, -1, min_val = -1000, max_val = 1000.0, increment = 100.0, agwStyle = FS.FS_RIGHT)
        self._fsBrushPowerOffset.SetDigits(6)
        self._fsBrushPowerOffset.SetFormat('%f')
        sizerBrushPowerOffset = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushPowerOffset.Add(staticBrushPowerOffset, 0, wx.CENTER, border = 5)
        sizerBrushPowerOffset.Add(self._fsBrushPowerOffset, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        # Up or down.
        self._ckUpDown = wx.CheckBox(self, -1, TD.TERRAIN_HEIGHT_BRUSH_UP_DOWN)
        sizerBrushUpDown = wx.BoxSizer(wx.HORIZONTAL)
        sizerBrushUpDown.Add(self._ckUpDown, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, border = 5)
        
        sizerBrushParam = wx.StaticBoxSizer(wx.StaticBox(self, -1, TD.TERRAN_HEIGHT_BRUSH_PARAM), wx.VERTICAL)
        sizerBrushParam.Add(sizerBrushSize, 0, wx.ALL|wx.EXPAND, border = 5)
        sizerBrushParam.Add(sizerBrushPowerFactor, 0, wx.ALL|wx.EXPAND, border = 5)
        sizerBrushParam.Add(sizerBrushPowerOffset, 0, wx.ALL|wx.EXPAND, border = 5)
        sizerBrushParam.Add(sizerBrushUpDown, 0, wx.ALL|wx.EXPAND, border = 5)
        return sizerBrushParam
        
    def __AddBrush(self, bmp, name):
        idx = self._ilBrush.Add(bmp)
        assert(self._listBrush.GetItemCount() == idx)
        self._listBrush.InsertImageStringItem(self._listBrush.GetItemCount(), name, idx)
        
    def __OnContextMenu(self, e):
        menu = wx.Menu()
        menu.Append(self._idMenuAddBrush, TD.MENU_ADD_TERRAIN_HEIGHT_BRUSH)
        menu.Append(self._idMenuRemoveBrush, TD.MENU_REMOVE_TERRAIN_HEIGHT_BRUSH)
        self.PopupMenu(menu)
        menu.Destroy()
        
    def __OnMenuAddBrush(self, e):
        dlg = wx.FileDialog(self, defaultDir = GLOBAL_SETTING._workDir, wildcard = u'All files (*.*)|*.*', style = wx.OPEN)
        path = ''
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()            

        dlg.Destroy()
        
        if not path:
            return

        path = REMOVE_ROOT_PATH(path)
            
        if not TERRAIN_EDITOR.AddTerrainHeightBrush(path):
            dlgMsg = wx.MessageDialog(self, TD.ERR_ADD_TERRAIN_HEIGHT_BRUSH_FAILED, TD.ERROR, wx.OK|wx.ICON_INFORMATION)
            dlgMsg.ShowModal()
            dlgMsg.Destroy()            
            return
            
        fullPath = GLOBAL_SETTING._workDir + path
        bmp = IL.LoadBitmap(fullPath, (BRUSH_SIZE, BRUSH_SIZE))
        if bmp:
            self.__AddBrush(bmp, path)
            GLOBAL_SETTING._terrainHeightBrushList.append(path)
        
    def __OnMenuRemoveBrush(self, e):
        idx = self._listBrush.GetNextItem(-1, state = wx.LIST_STATE_SELECTED)
        name = self._listBrush.GetItemText(idx)
        self._listBrush.DeleteItem(idx)
        for i in xrange(idx, self._listBrush.GetItemCount()):
            self._listBrush.SetItemImage(i, i)
            
        self._ilBrush.Remove(idx)
        TERRAIN_EDITOR.RemoveTerrainHeightBrush(name)
        GLOBAL_SETTING._terrainHeightBrushList.remove(name)
        
    def __OnBrushSelected(self, e):
        idx = e.m_itemIndex
        name = self._listBrush.GetItemText(idx)
        TERRAIN_EDITOR.UseHeightBrush(name)
        self.RefrehBrushParam()
        
    def RefrehBrushParam(self):
        brushCoreHandle = TERRAIN_EDITOR.GetCurrentHeightBrushHandle()
        if not brushCoreHandle:
            return
            
        size = TerrainHeightBrush.GetSize(brushCoreHandle)
        powerFactor = TerrainHeightBrush.GetPowerFactor(brushCoreHandle)
        powerOffset = TerrainHeightBrush.GetPowerOffset(brushCoreHandle)
        isPaintUp = TerrainHeightBrush.IsPaintUp(brushCoreHandle)
        self._fsBrushSize.SetValue(float(size))
        self._fsBrushPowerFactor.SetValue(float(powerFactor))
        self._fsBrushPowerOffset.SetValue(float(powerOffset))
        self._ckUpDown.SetValue(isPaintUp)